package de.tudarmstadt.fgbs.cafe.structure;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Observable;
import java.util.Set;

/**
 * A representation for a timetable (ger.: Fahrplan)
 * 
 * @author Christian Schlehuber
 * @version 0.2
 * 
 */
public class Fahrplan extends Observable implements Serializable {

    /**
     * UID for serialization of the class
     */
    private static final long serialVersionUID = -4254564375241022168L;

    /**
     * Name that was given for the current fahrplan
     */
    private String name;
    /**
     * List containing all zl in this fahrplan
     */
    private Map<String, Zuglauf> zuglaeufe;

    private int revision = 0;

    /**
     * Constructur for a new Fahrplan initializes all required fields
     */
    public Fahrplan() {
	zuglaeufe = new HashMap<String, Zuglauf>();
    }

    /**
     * NOT IMPLEMENTED
     * 
     * @param filename
     */
    public void export(String filename) {

    }

    /**
     * @return String the name
     */
    public String getName() {
	return name;
    }

    /**
     * @param name
     *            the name to set
     */
    public void setName(String name) {
	this.name = name;
    }

    /**
     * @return the zuglaeufe
     */
    public List<Zuglauf> getZuglaeufe() {
	List<Zuglauf> result = new ArrayList<Zuglauf>();
	result.addAll(zuglaeufe.values());
	return result;
    }

    /**
     * @param zuglaeufe
     *            the zuglaeufe to set
     */
    public void setZuglaeufe(List<Zuglauf> zuglaeufe) {
	for (Iterator<Zuglauf> it = zuglaeufe.iterator(); it.hasNext();) {
	    Zuglauf current = it.next();
	    this.zuglaeufe.put(current.getNumber(), current);
	}
    }

    /**
     * Method for retrieving a ZL for a given ZN
     * 
     * @param number
     *            String identifier of the Zuglauf
     * @return Zuglauf the wanted Zuglauf
     */
    public Zuglauf getZuglauf(String number) {
	return this.zuglaeufe.get(Zuglauf.getNumberFromDisplay(number));
    }

    /**
     * Method for notifying about changes to a ZL
     */
    public void notifyZLChange() {
	setChanged();
	notifyObservers();
    }

    public List<Zuglauf> getSortedZuglaeufe() {
	Set<String> zlNrs = zuglaeufe.keySet();
	ArrayList<String> zlList = new ArrayList<String>(zlNrs);
	Collections.sort(zlList);
	ArrayList<Zuglauf> result = new ArrayList<Zuglauf>();
	for (Iterator<String> it = zlList.iterator(); it.hasNext();) {
	    String zlnr = it.next();
	    result.add(zuglaeufe.get(zlnr));
	}
	return result;
    }

    /**
     * 
     * @param newZL
     * @return false, if a previous ZL was overwritten true, if everything went
     *         usual
     */
    public boolean addZuglauf(Zuglauf newZL) {
	Zuglauf previous = zuglaeufe.put(newZL.getNumber(), newZL);
	setChanged();
	notifyObservers();
	if (previous != null)
	    return false;
	else
	    return true;
    }

    public boolean removeZuglauf(String zlnr) {
	Zuglauf removed = zuglaeufe.remove(zlnr);
	setChanged();
	notifyObservers();
	if (removed != null)
	    return true;
	else
	    return false;
    }

    /**
     * @TODO check if change is possible according to former ZL
     * @param zn
     * @param minutes
     */
    public void incrementWholeZuglauf(String zn, int minutes) {
	Zuglauf current = zuglaeufe.get(zn);
	Zuglauf pre = null;
	Zuglauf succ = null;
	if (current.getKommtAusNr() != null && current.getKommtAusNr() != "")
	    pre = zuglaeufe.get(current.getKommtAusNr());
	if (current.getWirdZuNr() != null && current.getWirdZuNr() != "")
	    succ = zuglaeufe.get(current.getWirdZuNr());
	current.incrementWholeZuglauf(minutes);
	if (pre != null)
	    pre.incrementAbfahrtOnly(current.getStart().getBahnhof(), minutes);
	if (succ != null)
	    succ.incrementAnkunftOnly(current.getDestination().getBahnhof(),
		    minutes);
    }

    public void incrementAbfahrtZuglauf(String zn, Bahnhof bhf, int minutes) {
	Zuglauf current = zuglaeufe.get(zn);
	Zuglauf pre = null;
	if (current.getKommtAusNr() != null && current.getKommtAusNr() != "") {
	    String znPre = current.getKommtAusNr().replaceAll("[^\\d]", "");
	    pre = zuglaeufe.get(znPre);
	}

	if (current.incrementAbfahrtOnly(bhf, minutes)) {
	    if (bhf.getKurzbez().equals(
		    current.getStart().getBahnhof().getKurzbez())) {
		if (pre != null)
		    pre.incrementAbfahrtOnly(bhf, minutes);
	    }
	}
    }

    public void incrementAnkunftZuglauf(String zn, Bahnhof bhf, int minutes) {
	Zuglauf current = zuglaeufe.get(zn);
	Zuglauf succ = null;
	if (current.getWirdZuNr() != null && current.getWirdZuNr() != "") {
	    String znSucc = current.getWirdZuNr().replaceAll("[^\\d]", "");
	    succ = zuglaeufe.get(znSucc);
	}
	if (current.incrementAnkunftOnly(bhf, minutes)) {
	    if (bhf.getKurzbez().equals(
		    current.getDestination().getBahnhof().getKurzbez())) {
		if (succ != null)
		    succ.incrementAnkunftOnly(bhf, minutes);
	    }
	}

    }

    public void linkZuglaeufe() {
	ArrayList<Zuglauf> zlListe = new ArrayList<Zuglauf>();
	zlListe.addAll(zuglaeufe.values());

	for (Iterator<Zuglauf> it = zlListe.iterator(); it.hasNext();) {
	    Zuglauf current = it.next();
	}
    }

    /**
     * @return the revision
     */
    public int getRevision() {
	return revision;
    }

    /**
     * @param revision
     *            the revision to set
     */
    public void setRevision(int revision) {
	this.revision = revision;
    }

}
